﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;

namespace RazorTemplateEngine
{
    public class DynamicAssemblyCache
    {
        private string templatePath;
        private static Dictionary<string, DynamicAssembly> _innerCache = new Dictionary<string, DynamicAssembly>();
        private ExecuteContext _innerexecuteContext;
        public DynamicAssemblyCache(string OriginalTemplatePath, ExecuteContext executeContext)
        {
            if (string.IsNullOrEmpty(OriginalTemplatePath))
                throw new ArgumentNullException("OriginalTemplatePath");
            if (executeContext == null)
                throw new ArgumentNullException("controllerContext");
            _innerexecuteContext = executeContext;
            templatePath = OriginalTemplatePath;
        }

        public Assembly GetAssemblyFromRazor()
        {
            DynamicAssembly assembly = null;
            bool RecomplieRequest = false;
            TemplatePathResolver TemplateResolver = new TemplatePathResolver(_innerexecuteContext.srcTemplatePath);
            //if cached
            if (_innerCache != null && _innerCache.TryGetValue(templatePath, out assembly))
            {
                if (assembly != null)
                {

                    FileInfo fi = TemplateResolver.GetFileInfo(templatePath);
                    if (fi == null) throw new FileNotFoundException("templateFile");
                    if (fi.LastWriteTime <= assembly.LastWriteTime)
                        return assembly.Target;
                    else
                        RecomplieRequest = true;
                }
            }

            if (!TemplateResolver.FileExist(templatePath))
                throw new System.IO.FileNotFoundException(templatePath);

            //get tempalte source
            TemplateFile srcCode = TemplateResolver.ReadTemplate(templatePath);
            //parse to CodeCompileUnit
            RazorToCompileUnitParser parser = new RazorToCompileUnitParser();
            ParserRequestContext prContext = new ParserRequestContext();
            prContext.TemplateSource = srcCode.FileContent;
            CodeCompileUnit complieUnit = parser.Parse(prContext);
            //build to assembly
            DynamicCSharpCodeBuilder builder = new DynamicCSharpCodeBuilder(_innerexecuteContext.assemblyContext);
            CompilerResults compileResult = builder.Complie(complieUnit);

            //cache
            if (RecomplieRequest)
                _innerCache[templatePath] = new DynamicAssembly { Target = compileResult.CompiledAssembly, LastWriteTime = DateTime.Now };
            else
                _innerCache.Add(templatePath, new DynamicAssembly { Target = compileResult.CompiledAssembly, LastWriteTime = DateTime.Now });
            //return
            return compileResult.CompiledAssembly;
        }
    }
}
